package com.gitee.wsl.ext.math

import com.gitee.wsl.collections.iterator.SingletonIterator

fun <T:Comparable<T>> T.rangeSelf() = SingleRange(this)

class SingleRange<T:Comparable<T>>(override val start: T) :ClosedRange<T>,Iterable<T>{
    override val endInclusive: T = start
    override fun contains(value: T): Boolean = start==value

    override fun isEmpty(): Boolean = false
    override fun iterator(): Iterator<T> = SingletonIterator(start)

}

class DiscreteRange<T:Comparable<T>>(vararg values: T) :ClosedRange<T>,Iterable<T>{

    val typedValues = values.toList().sorted()

    override val start: T = typedValues.min()

    override val endInclusive: T = typedValues.max()

    override fun contains(value: T): Boolean = typedValues.contains(value)
    override fun iterator(): Iterator<T> = typedValues.iterator()

}

fun <T:Comparable<T>> ClosedRange<T>.overlaps(value: T): Boolean = value < endInclusive && value > start

/**
 * Returns true if this range is a subset of the given range in terms of min and max values.
 *
 * @param range The range to check
 * @return True if this range is a subset of the given range
 */
fun <T:Comparable<T>> ClosedRange<T>.isSubsetOf(range: ClosedRange<T>): Boolean = range.start <= start && range.endInclusive >= endInclusive

/**
 * Returns true if this range is a superset of the given range in terms of min and max values.
 *
 * @param range The range to check
 * @return True if this range is a superset of the given range
 */
fun <T:Comparable<T>> ClosedRange<T>.isSupersetOf(range: ClosedRange<T>): Boolean = range.start >= start && range.endInclusive <= endInclusive


/**
 * Get the difference of this range and the given range.
 *
 * @param range The range to difference with
 * @return The difference of this range and the given range
 */
fun <T:Comparable<T>> ClosedRange<T>.difference(range: ClosedRange<T>): List<T>{
    if(!(this is Iterable<*> && range is Iterable<*>)) return emptyList()
    val result = mutableListOf<T>()
    this.forEach { value->
        if (!range.contains(value))
            result.add(value as T)
    }
    return result
}

fun <T : Comparable<T>> ClosedRange<T>.intersect(other: ClosedRange<T>): Pair<T, T>? = when {
    start == other.start && endInclusive == other.endInclusive -> start to endInclusive
    start > other.endInclusive || other.start > endInclusive -> null
    else -> maxOf(start, other.start) to minOf(endInclusive, other.endInclusive)
}

fun IntRange.intersect(
    other: IntRange
): IntRange? = (this as ClosedRange<Int>).intersect(other as ClosedRange<Int>) ?.let {
    it.first .. it.second
}

fun LongRange.intersect(
    other: LongRange
): LongRange? = (this as ClosedRange<Long>).intersect(other as ClosedRange<Long>) ?.let {
    it.first .. it.second
}